import json
import threading
import os
from pathlib import Path
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, jsonify, Response
from ..core.machine_control import wash_tube, reaction, fill_tube, reset, empty_tube, force_clear
from ..core.shared import stop_event
from ..utils.config import REAGENT_FILE, INJECT_FILE, LOG_DIR, LOCK_FILE, CONFIG_DIR, BASE_DIR
from ..utils.simple_logging import SimpleLogger, get_app_logger, get_web_logger
import time
from ..core.snail_fun import Snail

# 初始化日志系统
SimpleLogger.init(BASE_DIR)
app_logger = get_app_logger("main")
web_logger = get_web_logger()

snail = Snail()
snail.tec_connected = snail.tec.connected

# 启动日志
app_logger.info("=" * 60)
app_logger.info(f"反应器控制系统启动 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
app_logger.info(f"工作目录: {Path.cwd()}")
app_logger.info(f"日志目录: {BASE_DIR / 'logs'}")
app_logger.info("=" * 60)

# 创建Flask应用，设置正确的模板和静态文件路径
from ..utils.config import BASE_DIR

app = Flask(__name__, 
           template_folder=str(BASE_DIR / 'templates'),
           static_folder=str(BASE_DIR / 'static'))

# ========== 系统状态管理 ==========
class SystemState:
    """系统状态管理器"""
    def __init__(self):
        self.current_reagent_config = None
        self.current_inject_config = None
        self.reagent_locked = False
        self.reaction_paused = False
        self.current_step_index = 0
        self.current_cycle_count = 0
        self.device_status = 'idle'  # idle, reacting, paused, error, initializing, washing, filling
        self.temperature = 25.0
        self.current_step_info = ""  # 当前步骤信息
        self.next_action_info = ""   # 下一个动作信息
        self.last_modified_time = None  # 文件最后修改时间
        self.tec_connected = False
        self.pump_connected = False
        self.tec_connected = snail.tec.connected
        self.pump_connected = snail.pump.ser is not None and snail.pump.ser.is_open
        self._state_file = CONFIG_DIR / 'system_state.json'
        self._file_lock = threading.Lock()
        self._load_state()
        self._monitor_thread = None
        self._monitor_running = False



        # 启动文件监测线程
        self._start_file_monitor()
    
    def _get_file_mtime(self):
        """获取状态文件的修改时间"""
        try:
            if self._state_file.exists():
                return self._state_file.stat().st_mtime
        except Exception:
            pass
        return None
    
    def _load_state(self):
        """从文件加载状态"""
        with self._file_lock:
            if self._state_file.exists():
                try:
                    with open(self._state_file, 'r', encoding='utf-8') as f:
                        state = json.load(f)
                        self.current_reagent_config = state.get('current_reagent_config')
                        self.current_inject_config = state.get('current_inject_config')
                        self.reagent_locked = Path(LOCK_FILE).exists()  
                        self.current_step_index = state.get('current_step_index', 0)
                        self.current_cycle_count = state.get('current_cycle_count', 0)
                        self.device_status = state.get('device_status', 'idle')
                        self.temperature = state.get('temperature', 25.0)
                        self.current_step_info = state.get('current_step_info', '')
                        self.next_action_info = state.get('next_action_info', '')
                        self.reaction_paused = state.get('reaction_paused', False)
                        
                        # 记录文件修改时间
                        self.last_modified_time = self._get_file_mtime()
                        
                        app_logger.info(f"系统状态已恢复: 试剂配置={self.current_reagent_config}, 反应流程={self.current_inject_config}, 状态={self.device_status}")
                except Exception as e:
                    app_logger.error(f"加载系统状态失败: {e}")
    
    def save_state(self):
        """保存状态到文件"""
        with self._file_lock:
            try:
                state = {

                    'current_reagent_config': self.current_reagent_config,
                    'current_inject_config': self.current_inject_config,
                    'reagent_locked' : self.reagent_locked,
                    'current_step_index': self.current_step_index,
                    'current_cycle_count': self.current_cycle_count,
                    'device_status': self.device_status,
                    'temperature': self.temperature,
                    'current_step_info': self.current_step_info,
                    'next_action_info': self.next_action_info,
                    'reaction_paused': self.reaction_paused,
                    'last_updated': datetime.now().isoformat()
                }
                with open(self._state_file, 'w', encoding='utf-8') as f:
                    json.dump(state, f, ensure_ascii=False, indent=2)
                
                # 更新文件修改时间
                self.last_modified_time = self._get_file_mtime()
            except Exception as e:
                app_logger.error(f"保存系统状态失败: {e}")
    
    def _start_file_monitor(self):
        self._monitor_running = True
        """启动文件监测线程"""
        def monitor():
            while True:
                try:
                    current_mtime = self._get_file_mtime()
                    if current_mtime and self.last_modified_time and current_mtime > self.last_modified_time:
                        self.tec_connected = snail.tec.connected
                        self.pump_connected = snail.pump.ser is not None and snail.pump.ser.is_open
                        app_logger.info("检测到system_state.json文件变化，重新加载状态")
                        self._load_state()
                except Exception as e:
                    app_logger.error(f"文件监测错误: {e}")
                time.sleep(1)  # 每秒检查一次
        
        monitor_thread = threading.Thread(target=monitor, daemon=True)
        monitor_thread.start()
        app_logger.info("文件监测线程已启动")
    
    def get_state_dict(self):
        with self._file_lock:
            return {
                'device_status': self.device_status,
                'temperature': self.temperature if self.tec_connected else None,
                'tec_connected': self.tec_connected,
                'pump_connected': self.pump_connected,
                'reagent_locked': self.reagent_locked,
                'reaction_paused': self.reaction_paused,
                'current_step_index': self.current_step_index,
                'current_cycle_count': self.current_cycle_count,
                'current_step_info': self.current_step_info,
                'next_action_info': self.next_action_info,
                'current_reagent_config': self.current_reagent_config,
                'current_inject_config': self.current_inject_config,
                'timestamp': datetime.now().isoformat()
            }

# 创建系统状态实例
system_state = SystemState()

# ========== 工具函数 ==========
def load_json(path, default=None):
    """加载JSON文件"""
    try:
        if path.exists():
            with open(path, "r", encoding="utf-8") as f:
                return json.load(f)
        return default if default is not None else []
    except Exception as e:
        app_logger.error(f"加载配置文件 {path} 失败: {str(e)}")
        return default if default is not None else []

def save_json(path, data):
    """保存JSON文件"""
    try:
        path = Path(path)
        path.parent.mkdir(parents=True, exist_ok=True)
        
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        app_logger.info(f"配置文件已保存: {path}")
        return True
    except Exception as e:
        app_logger.error(f"保存配置文件 {path} 失败: {str(e)}")
        return False

def get_config_display_name(filename):
    """获取配置的显示名称"""
    name = filename.replace('_reagents.json', '').replace('_inject.json', '')
    return name

# ========== SSE状态流 ==========
def status_stream():
    """服务器发送事件流，实时推送系统状态"""
    last_state = None
    while True:
        try:
            # 获取当前状态
            current_state = system_state.get_state_dict()
            
            # 只在状态变化时发送更新
            if current_state != last_state:
                yield f"data: {json.dumps(current_state, ensure_ascii=False)}\n\n"
                last_state = current_state.copy()
            else:
                # 发送心跳包
                yield f": heartbeat\n\n"
            
            time.sleep(0.5)  # 每0.5秒检查一次状态
        except Exception as e:
            app_logger.error(f"状态流推送错误: {e}")
            break

@app.route('/status_stream')
def stream_status():
    """SSE端点"""
    return Response(status_stream(), mimetype='text/event-stream')

@app.route('/status')
def status():
    """状态查询端点"""
    return jsonify(system_state.get_state_dict())

# ========== API路由 ==========

@app.route("/")
def index():
    """主页面"""
    return render_template("index.html")

@app.route("/api/system/status", methods=["GET"])
def get_system_status():
    """获取系统状态"""
    try:
        state_dict = system_state.get_state_dict()
        state_dict['success'] = True
        return jsonify(state_dict)
    except Exception as e:
        app_logger.error(f"获取系统状态失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/reagents", methods=["GET"])
def list_reagent_configs():
    """列出所有试剂配置"""
    try:
        configs = []
        for file in CONFIG_DIR.glob("*_reagents.json"):
            configs.append({
                'name': file.name,
                'display_name': get_config_display_name(file.name),
                'is_current': file.name == system_state.current_reagent_config
            })
        
        # 添加当前系统配置（如果存在）
        if REAGENT_FILE.exists():
            configs.insert(0, {
                'name': 'reagents.json',
                'display_name': '当前系统配置',
                'is_current': 'reagents.json' == system_state.current_reagent_config
            })
        
        return jsonify({'success': True, 'configs': configs})
    except Exception as e:
        app_logger.error(f"列出试剂配置失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/reagents/<config_name>", methods=["GET"])
def get_reagent_config(config_name):
    """获取特定试剂配置"""
    try:
        config_path = CONFIG_DIR / config_name
        if not config_path.exists():
            return jsonify({'success': False, 'message': '配置不存在'}), 404
        
        config = load_json(config_path)
        return jsonify({'success': True, 'config': config})
    except Exception as e:
        app_logger.error(f"获取试剂配置失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/reagents", methods=["POST"])
def save_reagent_config():
    """保存试剂配置"""
    try:
        data = request.json
        config_name = data.get('name', '').strip()
        config = data.get('config', [])
        
        if not config_name:
            return jsonify({'success': False, 'message': '配置名称不能为空'}), 400
        
        # 确保文件名格式
        if not config_name.endswith('_reagents.json'):
            config_name += '_reagents.json'
        
        config_path = CONFIG_DIR / config_name
        
        if save_json(config_path, config):
            return jsonify({'success': True, 'message': f'配置已保存: {config_name}'})
        else:
            return jsonify({'success': False, 'message': '保存失败'}), 500
    except Exception as e:
        app_logger.error(f"保存试剂配置失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/reagents/<config_name>", methods=["DELETE"])
def delete_reagent_config(config_name):
    """删除试剂配置"""
    try:
        if config_name == 'reagents.json':
            return jsonify({'success': False, 'message': '不能删除系统主配置'}), 400
        
        config_path = CONFIG_DIR / config_name
        if not config_path.exists():
            return jsonify({'success': False, 'message': '配置不存在'}), 404
        
        config_path.unlink()
        app_logger.info(f"删除试剂配置: {config_name}")
        
        return jsonify({'success': True, 'message': f'配置已删除: {config_name}'})
    except Exception as e:
        app_logger.error(f"删除试剂配置失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/system/reagent-config", methods=["POST"])
def apply_reagent_config():
    """应用试剂配置到系统"""
    try:
        if system_state.reagent_locked:
            return jsonify({'success': False, 'message': '试剂配置已锁定'}), 400
        
        data = request.json
        config_name = data.get('config_name', '').strip()
        config = data.get('config', [])
        
        # 保存到系统配置文件
        if save_json(REAGENT_FILE, config):
            system_state.current_reagent_config = config_name
            system_state.save_state()
            
            app_logger.info(f"应用试剂配置: {config_name}")
            return jsonify({
                'success': True,
                'message': '试剂配置已应用',
                'config_name': config_name
            })
        else:
            return jsonify({'success': False, 'message': '应用配置失败'}), 500
    except Exception as e:
        app_logger.error(f"应用试剂配置失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/injects", methods=["GET"])
def list_inject_configs():
    """列出所有反应流程配置"""
    try:
        configs = []
        for file in CONFIG_DIR.glob("*_inject.json"):
            # 读取配置以获取关联的试剂配置
            config_data = load_json(file)
            reagent_config = None
            
            # 检查是否有reagent_config字段
            if isinstance(config_data, dict):
                reagent_config = config_data.get('reagent_config')
            
            configs.append({
                'name': file.name,
                'display_name': get_config_display_name(file.name),
                'reagent_config': reagent_config,
                'is_current': file.name == system_state.current_inject_config
            })
        
        # 添加当前系统配置
        if INJECT_FILE.exists():
            configs.insert(0, {
                'name': 'inject_steps.json',
                'display_name': '当前系统流程',
                'reagent_config': system_state.current_reagent_config,
                'is_current': 'inject_steps.json' == system_state.current_inject_config
            })
        
        return jsonify({'success': True, 'configs': configs})
    except Exception as e:
        app_logger.error(f"列出反应流程失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/injects/<config_name>", methods=["GET"])
def get_inject_config(config_name):
    """获取特定反应流程配置"""
    try:
        config_path = CONFIG_DIR / config_name
        if not config_path.exists():
            return jsonify({'success': False, 'message': '配置不存在'}), 404
        
        config_data = load_json(config_path)
        
        # 兼容旧格式（纯步骤数组）和新格式（包含元数据）
        if isinstance(config_data, list):
            config = {'steps': config_data, 'reagent_config': None}
        else:
            config = config_data
        
        return jsonify({'success': True, 'config': config})
    except Exception as e:
        app_logger.error(f"获取反应流程失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/injects", methods=["POST"])
def save_inject_config():
    """保存反应流程配置"""
    try:
        data = request.json
        config_name = data.get('name', '').strip()
        reagent_config = data.get('reagent_config')
        steps = data.get('steps', [])
        
        if not config_name:
            return jsonify({'success': False, 'message': '配置名称不能为空'}), 400
        
        if not steps:
            return jsonify({'success': False, 'message': '至少需要一个步骤'}), 400
        
        # 确保文件名格式
        if not config_name.endswith('_inject.json'):
            config_name += '_inject.json'
        
        config_path = CONFIG_DIR / config_name
        
        # 保存配置（包含关联的试剂配置信息）
        config_data = {
            'reagent_config': reagent_config,
            'steps': steps,
            'created_time': datetime.now().isoformat()
        }
        
        if save_json(config_path, config_data):
            return jsonify({'success': True, 'message': f'流程已保存: {config_name}'})
        else:
            return jsonify({'success': False, 'message': '保存失败'}), 500
    except Exception as e:
        app_logger.error(f"保存反应流程失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/configs/injects/<config_name>", methods=["DELETE"])
def delete_inject_config(config_name):
    """删除反应流程配置"""
    try:
        if config_name == 'inject_steps.json':
            return jsonify({'success': False, 'message': '不能删除系统主流程'}), 400
        
        config_path = CONFIG_DIR / config_name
        if not config_path.exists():
            return jsonify({'success': False, 'message': '配置不存在'}), 404
        
        config_path.unlink()
        app_logger.info(f"删除反应流程: {config_name}")
        
        return jsonify({'success': True, 'message': f'流程已删除: {config_name}'})
    except Exception as e:
        app_logger.error(f"删除反应流程失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/system/inject-config", methods=["POST"])
def apply_inject_config():
    """应用反应流程到系统"""
    try:
        data = request.json
        config_name = data.get('config_name', '').strip()
        steps = data.get('steps', [])
        
        if not steps:
            return jsonify({'success': False, 'message': '至少需要一个步骤'}), 400
        
        # 转换为旧格式以兼容现有代码
        inject_data = []
        for i, step in enumerate(steps):
            inject_data.append({
                "index": i + 1,
                "reagent": step.get('reagent', ''),
                "cycles": step.get('times', 1),
                "timewait": step.get('timewait', 10),
                "temperature": step.get('temperature', 25)
            })
        
        # 保存到系统配置文件
        if save_json(INJECT_FILE, inject_data):
            system_state.current_inject_config = config_name
            system_state.save_state()
            
            app_logger.info(f"应用反应流程: {config_name} ({len(inject_data)}个步骤)")
            return jsonify({
                'success': True,
                'message': '反应流程已应用',
                'config_name': config_name,
                'step_count': len(inject_data)
            })
        else:
            return jsonify({'success': False, 'message': '应用流程失败'}), 500
    except Exception as e:
        app_logger.error(f"应用反应流程失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/device/operation", methods=["POST"])
def device_operation():
    """执行设备操作"""
    try:
        data = request.json
        action = data.get('action')
        
        if not action:
            return jsonify({'success': False, 'message': '未指定操作'}), 400
        
        # 执行相应操作
        if action == "reset":
            if Path(LOCK_FILE).exists():
                Path(LOCK_FILE).unlink()
            system_state.device_status = 'initializing'
            system_state.save_state()
            threading.Thread(target=reset).start()
            message = "设备初始化已启动"
            
        elif action == "wash":
            system_state.device_status = 'washing'
            system_state.save_state()
            threading.Thread(target=wash_tube).start()
            message = "清洗任务已启动"
            # 注意：实际清洗完成后应该在wash_tube函数中更新状态

        elif action == "empty":
            system_state.device_status = 'working'
            system_state.save_state()
            threading.Thread(target=empty_tube).start()
            message = "排空任务已启动"
            # 注意：实际排空完成后应该在empty_tube函数中更新状态

        elif action == "fill_tube":
            # 创建锁定文件
            Path(LOCK_FILE).touch()
            system_state.reagent_locked = True
            system_state.device_status = 'filling'
            system_state.save_state()
            
            # 准备试剂映射
            reagent_config = load_json(REAGENT_FILE)
            reagent_map = {
                item['reagent']: item['port']
                for item in reagent_config
                if 3 <= item['port'] <= 9 and item['reagent']
            }
            
            threading.Thread(target=fill_tube, args=(reagent_map,)).start()
            message = "填充管路任务已启动"
            
        elif action == "reaction":
            stop_event.clear()
            system_state.reaction_paused = False
            system_state.device_status = 'reacting'
            system_state.save_state()
            
            # 检查配置
            if not system_state.current_reagent_config:
                return jsonify({'success': False, 'message': '请先选择试剂配置'}), 400
            if not system_state.current_inject_config:
                return jsonify({'success': False, 'message': '请先选择反应流程'}), 400
            
            # 从保存的状态继续或从头开始
            threading.Thread(
                target=reaction, 
                args=(INJECT_FILE, REAGENT_FILE, stop_event, system_state)
            ).start()
            
            message = "反应流程已启动"

        elif action == "pause":
            if system_state.device_status == 'reacting':
                system_state.reaction_paused = True
                system_state.device_status = 'paused'
                system_state.save_state()
                message = "已暂停反应流程"
                app_logger.info(f"用户暂停反应流程")
            else:
                return jsonify({'success': False, 'message': '当前没有可暂停的反应'}), 400

        elif action == "resume":
            if system_state.device_status == 'paused':
                system_state.reaction_paused = False
                system_state.device_status = 'reacting'
                system_state.save_state()
                message = "已继续反应流程"
                app_logger.info(f"用户继续反应流程")
            else:
                return jsonify({'success': False, 'message': '当前没有可继续的反应'}), 400

        elif action == "stop":
            stop_event.set()
            system_state.reaction_paused = False
            system_state.current_step_index = 0
            system_state.current_cycle_count = 0
            system_state.device_status = 'idle'
            system_state.current_step_info = ""
            system_state.next_action_info = ""
            system_state.save_state()
            message = "已停止反应流程"
            app_logger.info(f"用户停止反应流程")
            
        else:
            return jsonify({'success': False, 'message': '未知操作'}), 400
        
        return jsonify({
            'success': True,
            'message': message,
            'device_status': system_state.device_status
        })
        
    except Exception as e:
        app_logger.error(f"设备操作失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/log")
def show_log():
    """显示系统日志"""
    try:
        from ..utils.config import BASE_DIR
        
        # 获取最新的日志文件
        log_files = []
        log_dir = BASE_DIR / "logs"
        
        # 收集所有日志文件
        for subdir in ["app", "hardware", "web"]:
            subdir_path = log_dir / subdir
            if subdir_path.exists():
                for log_file in subdir_path.glob("*.log"):
                    log_files.append((log_file, log_file.stat().st_mtime))
        
        if log_files:
            # 按修改时间排序，获取最新的
            log_files.sort(key=lambda x: x[1], reverse=True)
            latest_log = log_files[0][0]
            
            with open(latest_log, "r", encoding="utf-8") as f:
                log_content = f.read()[-10000:]  # 读取最后10000字符
                
            log_info = f"显示日志文件: {latest_log.name} (来自 {latest_log.parent.name}/)"
        else:
            log_content = "没有找到日志文件"
            log_info = ""
    except Exception as e:
        log_content = f"无法读取日志文件: {e}"
        log_info = ""
    
    return f"""
    <html>
    <head>
        <title>系统日志</title>
        <style>
            body {{ font-family: monospace; padding: 20px; background: #f5f5f5; }}
            pre {{ 
                white-space: pre-wrap; 
                background: white; 
                padding: 20px; 
                border-radius: 5px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }}
            .refresh-btn {{
                padding: 10px 20px;
                background: #3498db;
                color: white;
                border: none;
                border-radius: 5px;
                cursor: pointer;
                margin-bottom: 20px;
            }}
        </style>
    </head>
    <body>
        <button class="refresh-btn" onclick="location.reload()">刷新日志</button>
        <button class="refresh-btn" onclick="window.location='/'">返回主页</button>
        <button class="refresh-btn" onclick="window.location='/log-list'">查看所有日志</button>
        
        <div style="margin: 10px 0; padding: 10px; background: #e8f4f8; border-radius: 5px;">
            <strong>{log_info}</strong>
        </div>
        
        <pre>{log_content}</pre>
    </body>
    </html>
    """

@app.route("/log-list")
def log_list():
    """显示所有日志文件列表"""
    try:
        from ..utils.config import BASE_DIR
        
        log_dir = BASE_DIR / "logs"
        log_files_info = []
        
        # 收集所有日志文件信息
        for subdir in ["app", "hardware", "web", "errors"]:
            subdir_path = log_dir / subdir
            if subdir_path.exists():
                for log_file in subdir_path.glob("*.log*"):
                    size_mb = log_file.stat().st_size / 1024 / 1024
                    mtime = datetime.fromtimestamp(log_file.stat().st_mtime)
                    log_files_info.append({
                        'name': log_file.name,
                        'category': subdir,
                        'size': f"{size_mb:.2f} MB",
                        'modified': mtime.strftime('%Y-%m-%d %H:%M:%S'),
                        'path': f"{subdir}/{log_file.name}"
                    })
        
        # 按修改时间排序
        log_files_info.sort(key=lambda x: x['modified'], reverse=True)
        
        # 生成HTML表格
        table_rows = ""
        for log in log_files_info:
            table_rows += f"""
            <tr>
                <td><a href="/log-view?file={log['path']}">{log['name']}</a></td>
                <td>{log['category']}</td>
                <td>{log['size']}</td>
                <td>{log['modified']}</td>
            </tr>"""
        
        return f"""
        <html>
        <head>
            <title>日志文件列表</title>
            <style>
                body {{ font-family: Arial, sans-serif; padding: 20px; background: #f5f5f5; }}
                table {{ 
                    width: 100%; 
                    border-collapse: collapse; 
                    background: white;
                    border-radius: 5px;
                    overflow: hidden;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                }}
                th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
                th {{ background: #3498db; color: white; }}
                tr:hover {{ background: #f1f1f1; }}
                a {{ color: #3498db; text-decoration: none; }}
                a:hover {{ text-decoration: underline; }}
                .btn {{ 
                    padding: 10px 20px; 
                    background: #3498db; 
                    color: white; 
                    border: none; 
                    border-radius: 5px; 
                    cursor: pointer; 
                    margin: 10px 5px;
                    text-decoration: none;
                    display: inline-block;
                }}
            </style>
        </head>
        <body>
            <h2>系统日志文件列表</h2>
            
            <a href="/" class="btn">返回主页</a>
            <a href="/log" class="btn">查看最新日志</a>
            
            <table>
                <thead>
                    <tr>
                        <th>文件名</th>
                        <th>分类</th>
                        <th>大小</th>
                        <th>修改时间</th>
                    </tr>
                </thead>
                <tbody>
                    {table_rows}
                </tbody>
            </table>
            
            <div style="margin-top: 20px; padding: 15px; background: #e8f4f8; border-radius: 5px;">
                <h3>日志分类说明:</h3>
                <ul>
                    <li><strong>app/</strong> - 应用逻辑日志 (业务流程、状态管理)</li>
                    <li><strong>hardware/</strong> - 硬件设备日志 (泵、温控器)</li>
                    <li><strong>web/</strong> - Web服务日志 (HTTP请求、Flask)</li>
                    <li><strong>errors/</strong> - 错误专用日志 (详细错误信息)</li>
                </ul>
            </div>
        </body>
        </html>
        """
        
    except Exception as e:
        return f"获取日志列表失败: {e}"

@app.route("/log-view")
def log_view():
    """查看指定的日志文件"""
    try:
        from ..utils.config import BASE_DIR
        file_path = request.args.get('file', '')
        
        if not file_path:
            return "缺少文件参数"
        
        log_file = BASE_DIR / "logs" / file_path
        
        if not log_file.exists() or not log_file.is_file():
            return "日志文件不存在"
        
        # 安全检查，确保文件在logs目录下
        if not str(log_file.resolve()).startswith(str((BASE_DIR / "logs").resolve())):
            return "无效的文件路径"
        
        with open(log_file, "r", encoding="utf-8") as f:
            content = f.read()
            
        # 如果文件太大，只显示最后部分
        if len(content) > 50000:
            content = "... (文件过大，仅显示最后50000字符) ...\n\n" + content[-50000:]
        
        return f"""
        <html>
        <head>
            <title>查看日志: {file_path}</title>
            <style>
                body {{ font-family: monospace; padding: 20px; background: #f5f5f5; }}
                pre {{ 
                    white-space: pre-wrap; 
                    background: white; 
                    padding: 20px; 
                    border-radius: 5px;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                    max-height: 80vh;
                    overflow-y: auto;
                }}
                .btn {{ 
                    padding: 10px 20px;
                    background: #3498db;
                    color: white;
                    border: none;
                    border-radius: 5px;
                    cursor: pointer;
                    margin: 5px;
                    text-decoration: none;
                    display: inline-block;
                }}
            </style>
        </head>
        <body>
            <a href="/log-list" class="btn">返回日志列表</a>
            <a href="/" class="btn">返回主页</a>
            <button class="btn" onclick="location.reload()">刷新</button>
            
            <h3>日志文件: {file_path}</h3>
            <pre>{content}</pre>
        </body>
        </html>
        """
        
    except Exception as e:
        return f"查看日志失败: {e}"

# ========== 错误处理 ==========
@app.errorhandler(404)
def not_found(error):
    return jsonify({'success': False, 'message': '资源不存在'}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({'success': False, 'message': '服务器内部错误'}), 500

# ========== 应用启动 ==========
if __name__ == "__main__":
    try:
        # 启动时删除锁文件
        if Path(LOCK_FILE).exists():
            try:
                Path(LOCK_FILE).unlink()
                app_logger.info(f"启动时已删除锁文件：{LOCK_FILE}")
            except Exception as e:
                app_logger.error(f"启动时删除锁文件失败: {e}")
        
        # 重置设备状态
        system_state.device_status = 'idle'
        system_state.reaction_paused = False
        system_state.save_state()
        
        app_logger.info("Flask应用准备启动...")
        
        # 启动Flask应用
        app.run(host="0.0.0.0", port=5000, debug=False)
        
    except KeyboardInterrupt:
        app_logger.info("接收到中断信号，正在关闭应用...")
    except Exception as e:
        app_logger.error(f"应用启动失败: {e}")
    finally:
        # 确保程序退出时停止所有任务
        stop_event.set()
        system_state.save_state()
        app_logger.info("应用已安全关闭")



# ====== Pump 基础 API ======
@app.route("/api/pump/status", methods=["GET"])
def pump_status():
    try:
        port = snail.pump.get_current_port() or 0
        pos = snail.pump.query_pump_position() or 0
        spd = snail.pump.get_speed() or 0
        return jsonify({'success': True, 'port': port, 'position': pos, 'speed': spd})
    except Exception as e:
        app_logger.error(f"pump_status 失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/pump/speed", methods=["GET","PUT"])
def pump_speed():
    try:
        if request.method == "GET":
            spd = snail.pump.get_speed()
            return jsonify({'success': True, 'speed': spd})
        data = request.json or {}
        speed = int(data.get('speed', 500))
        now = snail.pump.set_speed(speed=speed)
        return jsonify({'success': True, 'speed': now})
    except Exception as e:
        app_logger.error(f"pump_speed 失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/pump/rotate", methods=["POST"])
def pump_rotate():
    try:
        port = int((request.json or {}).get('port'))
        ok = snail.pump.rotate_to_port(port_number=port)
        return jsonify({'success': bool(ok)})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 400

@app.route("/api/pump/zero", methods=["POST"])
def pump_zero():
    try:
        ok = snail.pump.move_pump_to_zero()
        return jsonify({'success': bool(ok)})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route("/api/pump/asp", methods=["POST"])
def pump_asp():
    try:
        data = request.json or {}
        vol = int(data.get('volume', 1000))
        port = int(data.get('port'))
        snail.pump.move_and_aspirate(volume=vol, port_number=port)
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 400

@app.route("/api/pump/disp", methods=["POST"])
def pump_disp():
    try:
        data = request.json or {}
        vol = int(data.get('volume', 1000))
        port = int(data.get('port'))
        snail.pump.move_and_dispense(volume=vol, port_number=port)
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 400

# ====== TEC 基础 API ======
@app.route("/api/tec/temperature", methods=["GET","PUT"])
def tec_temperature():
    try:
        if request.method == "GET":
            t = snail.tec.get_temperature()
            return jsonify({'success': True, 'temperature': t})
        data = request.json or {}
        t = float(data.get('target'))
        snail.tec.set_temperature(t)
        return jsonify({'success': True, 'target': t})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 400

@app.route("/api/tec/monitor/start", methods=["POST"])
def tec_monitor_start():
    interval = float((request.json or {}).get('interval', 5.0))
    snail.start_temperature_monitoring(interval=interval)
    return jsonify({'success': True})

@app.route("/api/tec/monitor/stop", methods=["POST"])
def tec_monitor_stop():
    snail.stop_temperature_monitoring()
    return jsonify({'success': True})
